"""
任务模型模块
定义任务数据结构和相关方法
"""

from datetime import datetime, date
from typing import Optional, Dict, Any
import json


class Task:
    """任务模型类"""
    
    # 有效的优先级选项
    VALID_PRIORITIES = ['high', 'medium', 'low']
    
    # 有效的状态选项
    VALID_STATUSES = ['todo', 'in_progress', 'completed']
    
    def __init__(self, 
                 title: str,
                 description: Optional[str] = None,
                 priority: str = 'medium',
                 status: str = 'todo',
                 category: Optional[str] = None,
                 due_date: Optional[str] = None,
                 task_id: Optional[int] = None,
                 created_at: Optional[str] = None,
                 updated_at: Optional[str] = None):
        """
        初始化任务对象
        
        Args:
            title: 任务标题
            description: 任务描述
            priority: 优先级 (high/medium/low)
            status: 状态 (todo/in_progress/completed)
            category: 分类
            due_date: 截止日期 (ISO 格式字符串)
            task_id: 任务 ID
            created_at: 创建时间
            updated_at: 更新时间
        """
        self.id = task_id
        self.title = self._validate_title(title)
        self.description = description
        self.priority = self._validate_priority(priority)
        self.status = self._validate_status(status)
        self.category = category
        self.due_date = self._validate_due_date(due_date)
        self.created_at = created_at or datetime.now().isoformat()
        self.updated_at = updated_at or datetime.now().isoformat()
    
    def _validate_title(self, title: str) -> str:
        """
        验证任务标题
        
        Args:
            title: 任务标题
            
        Returns:
            验证后的标题
            
        Raises:
            ValueError: 标题无效时抛出
        """
        if not title or not title.strip():
            raise ValueError("任务标题不能为空")
        
        title = title.strip()
        if len(title) > 200:
            raise ValueError("任务标题不能超过200个字符")
        
        return title
    
    def _validate_priority(self, priority: str) -> str:
        """
        验证优先级
        
        Args:
            priority: 优先级
            
        Returns:
            验证后的优先级
            
        Raises:
            ValueError: 优先级无效时抛出
        """
        if priority not in self.VALID_PRIORITIES:
            raise ValueError(f"无效的优先级: {priority}。有效选项: {', '.join(self.VALID_PRIORITIES)}")
        
        return priority
    
    def _validate_status(self, status: str) -> str:
        """
        验证状态
        
        Args:
            status: 状态
            
        Returns:
            验证后的状态
            
        Raises:
            ValueError: 状态无效时抛出
        """
        if status not in self.VALID_STATUSES:
            raise ValueError(f"无效的状态: {status}。有效选项: {', '.join(self.VALID_STATUSES)}")
        
        return status
    
    def _validate_due_date(self, due_date: Optional[str]) -> Optional[str]:
        """
        验证截止日期
        
        Args:
            due_date: 截止日期字符串
            
        Returns:
            验证后的截止日期
            
        Raises:
            ValueError: 日期格式无效时抛出
        """
        if due_date is None:
            return None
        
        try:
            # 尝试解析日期字符串
            if isinstance(due_date, str):
                # 支持多种日期格式
                for fmt in ['%Y-%m-%d', '%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%S']:
                    try:
                        datetime.strptime(due_date, fmt)
                        return due_date
                    except ValueError:
                        continue
                
                # 如果都不匹配，抛出错误
                raise ValueError("日期格式无效")
            
            return due_date
        except Exception:
            raise ValueError("截止日期格式无效，请使用 YYYY-MM-DD 格式")
    
    def to_dict(self) -> Dict[str, Any]:
        """
        将任务对象转换为字典
        
        Returns:
            任务数据字典
        """
        return {
            'id': self.id,
            'title': self.title,
            'description': self.description,
            'priority': self.priority,
            'status': self.status,
            'category': self.category,
            'due_date': self.due_date,
            'created_at': self.created_at,
            'updated_at': self.updated_at
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Task':
        """
        从字典创建任务对象
        
        Args:
            data: 任务数据字典
            
        Returns:
            任务对象
        """
        return cls(
            title=data.get('title'),
            description=data.get('description'),
            priority=data.get('priority', 'medium'),
            status=data.get('status', 'todo'),
            category=data.get('category'),
            due_date=data.get('due_date'),
            task_id=data.get('id'),
            created_at=data.get('created_at'),
            updated_at=data.get('updated_at')
        )
    
    @classmethod
    def from_db_row(cls, row) -> 'Task':
        """
        从数据库行创建任务对象
        
        Args:
            row: 数据库查询结果行
            
        Returns:
            任务对象
        """
        return cls(
            title=row['title'],
            description=row['description'],
            priority=row['priority'],
            status=row['status'],
            category=row['category'],
            due_date=row['due_date'],
            task_id=row['id'],
            created_at=row['created_at'],
            updated_at=row['updated_at']
        )
    
    def update(self, **kwargs) -> None:
        """
        更新任务属性
        
        Args:
            **kwargs: 要更新的属性
        """
        for key, value in kwargs.items():
            if hasattr(self, key):
                if key == 'title':
                    self.title = self._validate_title(value)
                elif key == 'priority':
                    self.priority = self._validate_priority(value)
                elif key == 'status':
                    self.status = self._validate_status(value)
                elif key == 'due_date':
                    self.due_date = self._validate_due_date(value)
                else:
                    setattr(self, key, value)
        
        self.updated_at = datetime.now().isoformat()
    
    def is_overdue(self) -> bool:
        """
        检查任务是否已过期
        
        Returns:
            如果任务已过期返回 True，否则返回 False
        """
        if not self.due_date or self.status == 'completed':
            return False
        
        try:
            due_date = datetime.fromisoformat(self.due_date.replace('Z', '+00:00'))
            return datetime.now() > due_date
        except Exception:
            return False
    
    def days_until_due(self) -> Optional[int]:
        """
        计算距离截止日期的天数
        
        Returns:
            距离截止日期的天数，如果没有截止日期返回 None
        """
        if not self.due_date:
            return None
        
        try:
            due_date = datetime.fromisoformat(self.due_date.replace('Z', '+00:00')).date()
            today = date.today()
            delta = due_date - today
            return delta.days
        except Exception:
            return None
    
    def get_priority_weight(self) -> int:
        """
        获取优先级权重（用于排序）
        
        Returns:
            优先级权重值
        """
        priority_weights = {
            'high': 3,
            'medium': 2,
            'low': 1
        }
        return priority_weights.get(self.priority, 2)
    
    def __str__(self) -> str:
        """
        返回任务的字符串表示
        
        Returns:
            任务的字符串描述
        """
        status_emoji = {
            'todo': '⏳',
            'in_progress': '🔄',
            'completed': '✅'
        }
        
        priority_emoji = {
            'high': '🔴',
            'medium': '🟡',
            'low': '🟢'
        }
        
        parts = [
            f"{status_emoji.get(self.status, '⏳')} [{self.id}]",
            f"{priority_emoji.get(self.priority, '🟡')} {self.title}"
        ]
        
        if self.category:
            parts.append(f"[{self.category}]")
        
        if self.due_date:
            parts.append(f"📅 {self.due_date}")
        
        return " ".join(parts)
    
    def __repr__(self) -> str:
        """
        返回任务的详细表示
        
        Returns:
            任务的详细字符串描述
        """
        return f"Task(id={self.id}, title='{self.title}', status='{self.status}', priority='{self.priority}')"